import { BadRequestException, HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common'
import { Like, Repository } from 'typeorm'
import { InjectRepository } from '@nestjs/typeorm'
import { formatDate } from 'src/utils'
import { Menu } from './entities/menu.entity'
import { CreateMenuDto } from './dto/create-menu.dto'
import { UpdateMenuDto } from './dto/update-menu.dto'

@Injectable()
export class MenuService {
  private logger = new Logger()

  @InjectRepository(Menu)
  private repository: Repository<Menu>

  initData() {
    const menu1 = new Menu()
    menu1.name = '菜单1'
    menu1.path = '/demo1'
    menu1.redirect = '/demo1-redirect'
    menu1.metaTitle = 'demo1-meta'
    menu1.pid = 0

    const menu2 = new Menu()
    menu2.name = '菜单2'
    menu2.path = '/demo2'
    menu2.redirect = '/demo2-redirect'
    menu2.metaTitle = 'demo2-meta'
    menu2.pid = 1

    const menu3 = new Menu()
    menu3.name = '菜单3'
    menu3.path = '/demo3'
    menu3.redirect = '/demo3-redirect'
    menu3.metaTitle = 'demo3-meta'
    menu3.pid = 0

    this.repository.insert([menu1, menu2, menu3])
  }

  async find(pageNo: number, pageSize: number, name: string) {
    // 边界条件检查
    if (pageNo <= 0 || pageSize <= 0) {
      throw new BadRequestException('页码和页数最小为 1')
    }

    const skipCount = (pageNo - 1) * pageSize
    const condition: Record<string, any> = {}
    if (name) {
      condition.name = Like(`%${name}%`)
    }

    const [menuList, totalCount] = await this.repository.findAndCount({
      skip: skipCount,
      take: pageSize,
      where: condition,
      relations: ['roles'],
    })

    const list = menuList.map((menu) => {
      return {
        ...menu,
        roles: menu.roles.map((role: any) => role.name),
        createTime: formatDate(menu.createTime),
        updateTime: formatDate(menu.updateTime),
      }
    })

    return {
      menuList: list,
      totalCount,
    }
  }

  async create(menuDto: CreateMenuDto) {
    try {
      // 原子性: 事务中的所有操作要么全部成功执行，要么全部不执行。如果事务中的任何一步失败，整个事务将回滚，保证数据库状态不变。
      // 隔离性: 多个事务并发执行时，每个事务的操作对其他事务是不可见的，直到事务提交。这可以防止并发操作导致的数据不一致。
      await this.repository.manager.transaction(async (transactionalEntityManager) => {
        const room = await transactionalEntityManager.findOne(Menu, {
          where: { path: menuDto.path },
        })

        if (room) {
          throw new BadRequestException('菜单已存在')
        }
        const createdMenu = await transactionalEntityManager.save(Menu, menuDto)
        return createdMenu
      })
      return '创建成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, MenuService.name)
        throw new HttpException('创建失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }

  async update(menuDto: UpdateMenuDto) {
    try {
      // 验证 menuDto.id 是否有效
      if (!menuDto.id) {
        throw new BadRequestException('无效的Menu ID')
      }

      const menu = await this.repository.findOneBy({
        id: menuDto.id,
      })

      if (!menu) {
        throw new BadRequestException('菜单不存在')
      }

      const updateMenu = Object.assign({}, menu, menuDto)

      // 如果需要自动更新updateTime需要使用save方法，update方法不会触发更新时间
      await this.repository.save(updateMenu)

      return '更新成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, MenuService.name)
        throw new HttpException('更新失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }

  async delete(id: number) {
    try {
      // 输入验证
      if (!id || id <= 0) {
        throw new BadRequestException('无效的id')
      }

      await this.repository.delete({ id })
      return '删除成功'
    }
    catch (e) {
      if (e instanceof BadRequestException) {
        // 如果是 BadRequestException，直接抛出
        throw e
      }
      else {
        // 其他错误，记录日志并抛出通用的 HttpException
        this.logger.error(`错误信息: ${e.message}`, MenuService.name)
        throw new HttpException('删除失败，请稍后再试', HttpStatus.INTERNAL_SERVER_ERROR)
      }
    }
  }
}
